
/*************************************************************************
 * All portions of code are copyright by their respective author/s.
 * Copyright (C) 2007      Bryan Christ <bryan.christ@hp.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *----------------------------------------------------------------------*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include "psthread.h"
#include "pseudo.h"
#include "scheduler.h"

ps_runq_t *psthread_init(int8_t scheduler)
{
	ps_runq_t		*run_q;

	run_q=(ps_runq_t*)calloc(1,sizeof(ps_runq_t));
	PS_TASK(run_q)->head=PS_TASK(run_q);
	PS_TASK(run_q)->next=PS_TASK(run_q);
	PS_TASK(run_q)->prev=PS_TASK(run_q);

	g_static_rec_mutex_init(&run_q->lock);

	if(scheduler == PS_SCHED_LEAPFROG)
	{
		PS_TASK(run_q)->callback=ps_sched_leapfrog;
	}

	return run_q;
}

ps_task_t* psthread_add(ps_runq_t *run_q,PSTHREAD callback,void *anything)
{
	ps_task_t	*task;

	if(run_q == NULL || callback == NULL) return NULL;

	RUNQ_LOCK(run_q);

	task=ps_task_create(callback,anything);
	task->head=PS_TASK(run_q);

	ps_task_append(task,PS_TASK(run_q),0);
	run_q->task_count++;

	RUNQ_UNLOCK(run_q);

	return task;
}

int8_t psthread_del(ps_runq_t *run_q,ps_task_t *task)
{
	uint16_t task_count;

	if(run_q == NULL || task == NULL) return -1;

	RUNQ_LOCK(run_q);

	task_count=run_q->task_count;
	if(task_count == 0)
	{
		RUNQ_UNLOCK(run_q);
		return -1;
	}

	ps_task_unlink(task);
	ps_task_destroy(task);

	RUNQ_UNLOCK(run_q);

	return 0;
}

void psthread_run(ps_runq_t *run_q,uint16_t tasks)
{
	ps_task_t	*runq_task;
   int16_t     retval;
	uint16_t		i;

	if(run_q == NULL) return;

	RUNQ_LOCK(run_q);

	if(run_q->task_count == 0)
	{
		RUNQ_UNLOCK(run_q);
		return;
	}

	if(tasks == 0) tasks=1;

	for(i=0;i < tasks;i++)
	{
		runq_task=PS_TASK(run_q);
		retval=runq_task->callback(runq_task,runq_task->anything);
	}

	RUNQ_UNLOCK(run_q);
	return;
}
